﻿using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace BToolkit
{
    public class TCPServer
    {
        private TcpListener tcpListener;
        private Thread listenThread;
        private ConcurrentDictionary<int, TcpClient> clients = new ConcurrentDictionary<int, TcpClient>();
        private int clientIdCounter = 0;

        public TCPServer()
        {
            MainThreadHelper.Init();
        }

        public void StartServer(int port)
        {
            try
            {
                tcpListener = new TcpListener(IPAddress.Any, port);
                listenThread = new Thread(new ThreadStart(ListenForClients));
                listenThread.Start();
            }
            catch (Exception ex)
            {
                UnityEngine.Debug.LogError($"[TCPServer]服务器启动失败：{ex}");
            }
        }

        private void ListenForClients()
        {
            tcpListener.Start();
            while (true)
            {
                TcpClient client = tcpListener.AcceptTcpClient();
                int clientId = ++clientIdCounter;
                clients.TryAdd(clientId, client);
                Thread clientThread = new Thread(() => HandleClientComm(client, clientId));
                clientThread.Start();
            }
        }

        private void HandleClientComm(TcpClient client, int clientId)
        {
            UnityEngine.Debug.Log("[TCPServer]有新客户端连接");
            //开始监听客户发来的消息
            NetworkStream stream = client.GetStream();
            byte[] buffer = new byte[4096];
            int bytesRead;
            while (true)
            {
                bytesRead = 0;
                try
                {
                    bytesRead = stream.Read(buffer, 0, 4096);
                }
                catch
                {
                    break;
                }
                if (bytesRead == 0)
                {
                    break;
                }
                string msg = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                //UnityEngine.Debug.Log($"[TCPServer]服务端收到消息：{msg}");
                ProtoBase protoBase = LitJson.JsonMapper.ToObject<ProtoBase>(msg);
                protoBase.fromClientId = clientId;
                TransmitMessage(protoBase);
            }
            clients.TryRemove(clientId, out _);
            client.Close();
        }

        private void TransmitMessage(ProtoBase protoBase)
        {
            byte[] buffer = Encoding.UTF8.GetBytes(LitJson.JsonMapper.ToJson(protoBase));
            foreach (var kvp in clients)
            {
                bool canSend;
                if (protoBase.sendBackToMeOnly)
                {
                    //UnityEngine.Debug.Log($"[TCPServer]服务转发消息(仅发回给发送者客户端，目的是告知客户端分配到的clientId) 发送者：{protoBase.fromClientId}   内容：{LitJson.JsonMapper.ToJson(protoBase)}");
                    canSend = kvp.Key == protoBase.fromClientId;
                }
                else if (protoBase.toClientId == -1)
                {
                    //UnityEngine.Debug.Log($"[TCPServer]服务转发消息(排除发送者客户端) 发送者：{protoBase.fromClientId}   内容：{LitJson.JsonMapper.ToJson(protoBase)}");
                    canSend = kvp.Key != protoBase.fromClientId;
                }
                else if (protoBase.toClientId == 0)
                {
                    //UnityEngine.Debug.Log($"[TCPServer]服务转发消息(全部客户端) 发送者：{protoBase.fromClientId}   内容：{LitJson.JsonMapper.ToJson(protoBase)}");
                    canSend = true;
                }
                else
                {
                    //UnityEngine.Debug.Log($"[TCPServer]服务转发消息(指定客户端id) 发送者：{protoBase.fromClientId}   内容：{LitJson.JsonMapper.ToJson(protoBase)}");
                    canSend = kvp.Key == protoBase.toClientId;
                }
                if (canSend)
                {
                    NetworkStream stream = kvp.Value.GetStream();
                    //UnityEngine.Debug.Log($"[TCPServer]stream.CanWrite：{stream.CanWrite}");
                    if (stream.CanWrite)
                    {
                        try
                        {
                            stream.Write(buffer, 0, buffer.Length);
                        }
                        catch (Exception ex)
                        {
                            UnityEngine.Debug.LogError($"[TCPServer]服务器转发消息失败：{ex}");
                        }
                    }
                }
            }
        }

        public void StopServer()
        {
            try
            {
                listenThread.Abort();
                tcpListener.Stop();
                foreach (var client in clients.Values)
                {
                    client.Close();
                }
                clients.Clear();
            }
            catch (Exception ex)
            {
                UnityEngine.Debug.LogError($"[TCPServer]服务器关闭失败：{ex}");
            }
        }
    }
}